import os
import chardet
import subprocess
import configparser
import sys
from PyQt5 import QtWidgets, QtGui, QtCore

class ConfigSearchApp(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.load_config()
        self.read_conf_files()

    def initUI(self):
        self.setWindowTitle('配置文件搜索')
        self.setGeometry(100, 100, 1400, 800)

        layout = QtWidgets.QVBoxLayout()

        search_layout = QtWidgets.QHBoxLayout()
        search_label = QtWidgets.QLabel('请输入要搜索的注释内容:')
        self.search_entry = QtWidgets.QLineEdit()
        self.search_entry.returnPressed.connect(self.on_search)
        search_button = QtWidgets.QPushButton('搜索')
        search_button.clicked.connect(self.on_search)

        search_layout.addWidget(search_label)
        search_layout.addWidget(self.search_entry)
        search_layout.addWidget(search_button)

        editor_layout = QtWidgets.QHBoxLayout()
        editor_label = QtWidgets.QLabel('默认打开编辑器:')
        self.editor_var = QtWidgets.QButtonGroup(self)
        self.notepad_radio = QtWidgets.QRadioButton('Notepad++')
        self.vscode_radio = QtWidgets.QRadioButton('VSCode')
        self.sublime_radio = QtWidgets.QRadioButton('Sublime')

        self.notepad_radio.setEnabled(False)
        self.vscode_radio.setEnabled(False)
        self.sublime_radio.setEnabled(False)

        self.editor_var.addButton(self.notepad_radio)
        self.editor_var.addButton(self.vscode_radio)
        self.editor_var.addButton(self.sublime_radio)

        editor_layout.addWidget(editor_label)
        editor_layout.addWidget(self.notepad_radio)
        editor_layout.addWidget(self.vscode_radio)
        editor_layout.addWidget(self.sublime_radio)

        self.tree = QtWidgets.QTreeWidget()
        self.tree.setColumnCount(4)
        self.tree.setHeaderLabels(['键', '值', '注释', '文件路径'])
        self.tree.itemSelectionChanged.connect(self.on_tree_select)
        self.tree.itemDoubleClicked.connect(self.on_tree_double_click)

        self.edit_text = QtWidgets.QTextEdit()
        self.add_button = QtWidgets.QPushButton('添加到import')
        self.add_button.clicked.connect(self.add_to_import)
        self.add_button.setVisible(False)

        layout.addLayout(search_layout)
        layout.addLayout(editor_layout)
        layout.addWidget(self.tree)
        layout.addWidget(self.edit_text)
        layout.addWidget(self.add_button)

        self.setLayout(layout)

    def load_config(self):
        self.config = configparser.ConfigParser()
        config_file_path = 'dsconfig.ini'
        if not os.path.exists(config_file_path):
            QtWidgets.QMessageBox.critical(self, "错误", "配置文件 dsconfig.ini 不存在。")
            sys.exit(1)
        else:
            self.config.read(config_file_path)

        self.root_directory = self.config.get('Server', 'Path', fallback='').replace("\\", "/")
        if not self.root_directory:
            QtWidgets.QMessageBox.critical(self, "错误", "根目录未在配置文件中指定。")
            sys.exit(1)

        self.directory = os.path.join(self.root_directory, 'conf/battle').replace("\\", "/")
        self.import_directory = os.path.join(self.root_directory, 'conf/import').replace("\\", "/")

        if not os.path.exists(self.import_directory):
            QtWidgets.QMessageBox.critical(self, "错误", "conf/import 目录不存在。")
            sys.exit(1)

        self.notepad_plus_plus = self.config.get('Editors', 'Notepad++', fallback=None)
        self.vscode = self.config.get('Editors', 'VSCode', fallback=None)
        self.sublime = self.config.get('Editors', 'Sublime', fallback=None)

        self.notepad_plus_plus_exists = self.notepad_plus_plus if self.notepad_plus_plus and os.path.exists(self.notepad_plus_plus) else None
        self.vscode_exists = self.vscode if self.vscode and os.path.exists(self.vscode) else None
        self.sublime_exists = self.sublime if self.sublime and os.path.exists(self.sublime) else None

        self.default_editor = self.config.get('Settings', 'DefaultEditor', fallback='Notepad++')

        if self.notepad_plus_plus_exists:
            self.notepad_radio.setEnabled(True)
        if self.vscode_exists:
            self.vscode_radio.setEnabled(True)
        if self.sublime_exists:
            self.sublime_radio.setEnabled(True)

        if self.default_editor == "Notepad++" and self.notepad_plus_plus_exists:
            self.notepad_radio.setChecked(True)
        elif self.default_editor == "VSCode" and self.vscode_exists:
            self.vscode_radio.setChecked(True)
        elif self.default_editor == "Sublime" and self.sublime_exists:
            self.sublime_radio.setChecked(True)

    def read_conf_files(self):
        self.config_data = {}
        conf_files = [f for f in os.listdir(self.directory) if f.endswith('.conf')]
        import_files = [f for f in os.listdir(self.import_directory) if f.endswith('.txt')]

        for import_file in import_files:
            file_path = os.path.join(self.import_directory, import_file).replace("\\", "/")
            relative_file_path = os.path.relpath(file_path, start=self.root_directory).replace("\\", "/")
            with open(file_path, 'rb') as file:
                raw_data = file.read()
                result = chardet.detect(raw_data)
                encoding = result['encoding']

            with open(file_path, 'r', encoding=encoding, errors='ignore') as file:
                lines = file.readlines()

            current_key = None
            comment = ""
            full_comment = ""
            line_number = 0
            for line in lines:
                line_number += 1
                line = line.rstrip()
                if line.startswith('//'):
                    if full_comment:
                        full_comment += "\n" + line
                    else:
                        full_comment = line
                    if not comment:
                        comment = line[2:].strip()
                elif ':' in line:
                    key, value = map(str.strip, line.split(':', 1))
                    if key:
                        self.config_data[key] = {'value': value, 'comment': comment, 'full_comment': full_comment, 'file_path': relative_file_path, 'absolute_file_path': file_path, 'line_number': line_number}
                        current_key = key
                    comment = ""
                    full_comment = ""
                else:
                    current_key = None

        for conf_file in conf_files:
            file_path = os.path.join(self.directory, conf_file).replace("\\", "/")
            relative_file_path = os.path.relpath(file_path, start=self.root_directory).replace("\\", "/")
            with open(file_path, 'rb') as file:
                raw_data = file.read()
                result = chardet.detect(raw_data)
                encoding = result['encoding']

            with open(file_path, 'r', encoding=encoding, errors='ignore') as file:
                lines = file.readlines()

            current_key = None
            comment = ""
            full_comment = ""
            line_number = 0
            for line in lines:
                line_number += 1
                line = line.rstrip()
                if line.startswith('//'):
                    if full_comment:
                        full_comment += "\n" + line
                    else:
                        full_comment = line
                    if not comment:
                        comment = line[2:].strip()
                elif ':' in line:
                    key, value = map(str.strip, line.split(':', 1))
                    if key and key not in self.config_data:
                        self.config_data[key] = {'value': value, 'comment': comment, 'full_comment': full_comment, 'file_path': relative_file_path, 'absolute_file_path': file_path, 'line_number': line_number}
                        current_key = key
                    comment = ""
                    full_comment = ""
                else:
                    current_key = None

    def on_search(self):
        self.read_conf_files()
        search_term = self.search_entry.text().lower()
        results = {key: data for key, data in self.config_data.items() if search_term in data['full_comment'].lower()}

        self.tree.clear()
        if results:
            for key, data in results.items():
                item = QtWidgets.QTreeWidgetItem([key, data['value'], data['comment'], data['file_path']])
                self.tree.addTopLevelItem(item)
            self.adjust_column_widths()
        else:
            item = QtWidgets.QTreeWidgetItem(["未找到匹配的键。", "", "", ""])
            self.tree.addTopLevelItem(item)
            self.edit_text.clear()
            self.add_button.setVisible(False)

    def adjust_column_widths(self):
        for i in range(self.tree.columnCount()):
            self.tree.resizeColumnToContents(i)

    def on_tree_select(self):
        selected_items = self.tree.selectedItems()
        if selected_items:
            item = selected_items[0]
            key = item.text(0)
            full_comment = self.config_data[key]['full_comment']
            self.edit_text.setText(f"{full_comment}\n{key}: {item.text(1)}\n\n文件路径: {item.text(3)}\n")

            if item.text(3) == "conf/import/battle_conf.txt":
                self.add_button.setVisible(False)
            else:
                self.add_button.setVisible(True)

    def on_tree_double_click(self, item, column):
        key = item.text(0)
        absolute_file_path = self.config_data[key]['absolute_file_path']
        line_number = self.config_data[key]['line_number']

        editor = self.editor_var.checkedButton()
        if editor is None:
            QtWidgets.QMessageBox.information(self, "信息", "没有可用的编辑器，使用系统默认记事本打开。")
            try:
                if os.name == 'nt':  # Windows
                    subprocess.Popen(['notepad.exe', absolute_file_path], creationflags=subprocess.CREATE_NO_WINDOW)
                elif os.name == 'posix':  # macOS or Linux
                    subprocess.Popen(['open', absolute_file_path] if sys.platform == 'darwin' else ['xdg-open', absolute_file_path])
            except Exception as e:
                QtWidgets.QMessageBox.critical(self, "错误", f"打开文件时出错: {e}")
            return

        editor_text = editor.text()
        if editor_text == "Notepad++" and self.notepad_plus_plus_exists:
            subprocess.Popen([self.notepad_plus_plus, "-n{}".format(line_number), absolute_file_path])
        elif editor_text == "VSCode" and self.vscode_exists:
            command = [self.vscode, "-g", "{}:{}".format(absolute_file_path, line_number)]
            try:
                result = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                stdout, stderr = result.communicate()
            except Exception as e:
                QtWidgets.QMessageBox.critical(self, "错误", f"运行 VSCode 时出错: {e}")
        elif editor_text == "Sublime" and self.sublime_exists:
            subprocess.Popen([self.sublime, "{}:{}".format(absolute_file_path, line_number)])
        else:
            QtWidgets.QMessageBox.information(self, "信息", "没有可用的编辑器，使用系统默认记事本打开。")
            try:
                if os.name == 'nt':  # Windows
                    subprocess.Popen(['notepad.exe', absolute_file_path], creationflags=subprocess.CREATE_NO_WINDOW)
                elif os.name == 'posix':  # macOS or Linux
                    subprocess.Popen(['open', absolute_file_path] if sys.platform == 'darwin' else ['xdg-open', absolute_file_path])
            except Exception as e:
                QtWidgets.QMessageBox.critical(self, "错误", f"打开文件时出错: {e}")

    def add_to_import(self):
        selected_items = self.tree.selectedItems()
        if selected_items:
            item = selected_items[0]
            key = item.text(0)
            value = item.text(1)
            full_comment = self.config_data[key]['full_comment']
            file_path = os.path.join(self.import_directory, 'battle_conf.txt').replace("\\", "/")
            relative_file_path = os.path.relpath(file_path, start=self.root_directory).replace("\\", "/")

            with open(file_path, 'a', encoding='utf-8') as file:
                file.write(f"\n")
                file.write(f"{full_comment}\n")
                file.write(f"{key}: {value}\n")

            self.config_data[key] = {
                'value': value,
                'comment': self.config_data[key]['comment'],
                'full_comment': full_comment,
                'file_path': relative_file_path,
                'absolute_file_path': file_path,
                'line_number': self.config_data[key]['line_number']
            }

            self.on_search()
            self.edit_text.setText(f"{full_comment}\n{key}: {value}\n\n文件路径: {relative_file_path}\n")
            self.add_button.setVisible(False)
            self.open_file_in_editor(file_path)

    def open_file_in_editor(self, file_path):
        editor = self.editor_var.checkedButton().text()
        try:
            if editor == "Notepad++" and self.notepad_plus_plus_exists:
                subprocess.Popen([self.notepad_plus_plus, file_path])
            elif editor == "VSCode" and self.vscode_exists:
                command = [self.vscode, "-g", "{}:{}".format(file_path, "999999")]
                subprocess.Popen(command)
            elif editor == "Sublime" and self.sublime_exists:
                subprocess.Popen([self.sublime, "{}:{}".format(file_path, "999999")])
            else:
                subprocess.Popen(["notepad.exe", file_path])
        except Exception as e:
            QtWidgets.QMessageBox.critical(self, "错误", f"无法打开文件: {e}")

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = ConfigSearchApp()
    ex.show()
    sys.exit(app.exec_())